﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Kinect.Toolbox.Record;
using Microsoft.Kinect;
using Kinect.Toolbox;
using System.IO;
using Microsoft.Win32;
using System.Threading;
using System.Windows.Threading;
using System.Timers;
using System.ComponentModel;


namespace TigerControl
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        // Prepare the Kinect Sensor and other stuff
        BackgroundWorker worker = new BackgroundWorker();
        KinectSensor kinectSensor;
        readonly ColorStreamManager colorManager = new ColorStreamManager();
        SkeletonDisplayManager skeletonDisplayManager;
        KinectRecorder recorder;
        KinectReplay replay;
        private Skeleton[] skeletons;
        BindableNUICamera nuiCamera;
        readonly ContextTracker contextTracker = new ContextTracker();
        int frameSkip = 1;

        System.Timers.Timer time = new System.Timers.Timer(1000);

        public MainWindow()
        {
            InitializeComponent();
            LoadKinect();
        }

       
        // Check Kinect Status
        public void LoadKinect()
        {
            try
            {
                KinectSensor.KinectSensors.StatusChanged += Kinects_StatusChanged;
                foreach (KinectSensor kinect in KinectSensor.KinectSensors)
                {
                    if (kinect.Status == KinectStatus.Connected)
                    {
                        kinectSensor = kinect;
                        break;
                    }
                }

                if (KinectSensor.KinectSensors.Count == 0)
                {
                    MessageBox.Show("No Kinect found");
                }
                else
                {
                    KinectInitialize();
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }

        // Kinect Initialize
        private void KinectInitialize()
        {
            if (kinectSensor == null)
            {
                return;
            }

            kinectSensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
            kinectSensor.ColorFrameReady += kinectRuntime_ColorFrameReady;

            // Smooth kinect of SkeletonStream            
            kinectSensor.SkeletonStream.Enable(new TransformSmoothParameters
            {
                Smoothing = 0.75f,
                Correction = 0.1f,
                Prediction = 0.0f,
                JitterRadius = 0.05f,
                MaxDeviationRadius = 0.08f
            });


            kinectSensor.SkeletonFrameReady += kinectRuntime_SkeletonFrameReady;

            skeletonDisplayManager = new SkeletonDisplayManager(kinectSensor, kinectCanvas);

            kinectSensor.Start();

            nuiCamera = new BindableNUICamera(kinectSensor);

            kinectDisplay.DataContext = colorManager;
        }

        void Kinects_StatusChanged(object sender, StatusChangedEventArgs e)
        {
            switch (e.Status)
            {
                case KinectStatus.Connected:
                    if (kinectSensor == null)
                    {
                        kinectSensor = e.Sensor;
                        KinectInitialize();
                    }
                    break;
                case KinectStatus.Disconnected:
                    if (kinectSensor == e.Sensor)
                    {
                        Clean();
                        MessageBox.Show("Kinect was disconnected");
                    }
                    break;
                case KinectStatus.NotReady:
                    break;
                case KinectStatus.NotPowered:
                    if (kinectSensor == e.Sensor)
                    {
                        Clean();
                        MessageBox.Show("Kinect is no more powered");
                    }
                    break;
                default:
                    MessageBox.Show("Unhandled Status: " + e.Status);
                    break;
            }
        }

        // Support method for Color Frame
        void kinectRuntime_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
        {
            if (replay != null && !replay.IsFinished)
                return;

            using (var frame = e.OpenColorImageFrame())
            {
                if (frame == null)
                    return;

                if (recorder != null && ((recorder.Options & KinectRecordOptions.Color) != 0))
                {
                    if (frame.FrameNumber % frameSkip == 0)
                    {
                        recorder.Record(frame);
                    }
                }

                colorManager.Update(frame);
            }
        }

        // Support method for Skeleton Frame
        void kinectRuntime_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {
            if (replay != null && !replay.IsFinished)
                return;

            using (SkeletonFrame frame = e.OpenSkeletonFrame())
            {
                if (frame == null)
                    return;

                if (recorder != null && ((recorder.Options & KinectRecordOptions.Skeletons) != 0))
                {
                    if (frame.FrameNumber % frameSkip == 0)
                    {
                        //worker.ReportProgress(0, frame);
                        recorder.Record(frame);
                    }
                }

                frame.GetSkeletons(ref skeletons);

                if (skeletons.All(s => s.TrackingState == SkeletonTrackingState.NotTracked))
                    return;

                ProcessFrame(frame);
            }
        }

        void ProcessFrame(ReplaySkeletonFrame frame)
        {
            Dictionary<int, string> stabilities = new Dictionary<int, string>();
            foreach (var skeleton in frame.Skeletons)
            {
                if (skeleton.TrackingState != SkeletonTrackingState.Tracked)
                    continue;

                //if (eyeTracker == null)
                //    eyeTracker = new EyeTracker(kinectSensor);

                //eyeTracker.Track(skeleton);

                contextTracker.Add(skeleton.Position.ToVector3(), skeleton.TrackingId);
                stabilities.Add(skeleton.TrackingId, contextTracker.IsStableRelativeToCurrentSpeed(skeleton.TrackingId) ? "Stable" : "Non stable");
                if (!contextTracker.IsStableRelativeToCurrentSpeed(skeleton.TrackingId))
                    continue;

                //if (eyeTracker.IsLookingToSensor.HasValue && eyeTracker.IsLookingToSensor == false)
                //    continue;

                foreach (Joint joint in skeleton.Joints)
                {
                    if (joint.TrackingState != JointTrackingState.Tracked)
                        continue;

                    //if (joint.JointType == JointType.HandRight)
                    //{
                    //    circleGestureRecognizer.Add(joint.Position, kinectSensor);
                    //}
                    //else if (joint.JointType == JointType.HandLeft)
                    //{
                    //    swipeGestureRecognizer.Add(joint.Position, kinectSensor);
                    //    if (controlMouse.IsChecked == true)
                    //        MouseController.Current.SetHandPosition(kinectSensor, joint, skeleton);
                    //}
                }

                //algorithmicPostureRecognizer.TrackPostures(skeleton);
                //templatePostureDetector.TrackPostures(skeleton);

                //if (recordNextFrameForPosture)
                //{
                //    templatePostureDetector.AddTemplate(skeleton);
                //    recordNextFrameForPosture = false;
                //}
            }

            skeletonDisplayManager.Draw(frame.Skeletons, false);

            //stabilitiesList.ItemsSource = stabilities;
        }


        private void Clean()
        {


            if (recorder != null)
            {
                recorder.Stop();
                recorder = null;
            }



            if (kinectSensor != null)
            {
                kinectSensor.SkeletonFrameReady -= kinectRuntime_SkeletonFrameReady;
                kinectSensor.ColorFrameReady -= kinectRuntime_ColorFrameReady;
                kinectSensor.Stop();
                kinectSensor = null;
            }
        }


        private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            this.DragMove();
        }

        private void MinBtn_Click(object sender, RoutedEventArgs e)
        {
            if (this.WindowState != System.Windows.WindowState.Minimized)
            {
                this.WindowState = System.Windows.WindowState.Minimized;
            }
        }

        private void CloseBtn_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        private void RecordBtn_Click(object sender, RoutedEventArgs e)
        {
            if (this.RecordBtn.Content.ToString() == "RECORD")
            {
                if (recorder != null)
                {
                    return;
                }

                SaveFileDialog saveFileDialog = new SaveFileDialog { Title = "Select filename", Filter = "Replay files|*.replay" };

                if (saveFileDialog.ShowDialog() == true)
                {
                    DirectRecord(saveFileDialog.FileName);
                }
            }
            else
            {
                if (recorder != null)
                {
                    recorder.Stop();
                    time.Stop();
                    recorder = null;
                    this.RecordBtn.Content = "RECORD";
                }
            }
        }

        private void DirectRecord(string targetFileName)
        {
            Stream recordStream = File.Create(targetFileName);
            //recorder = new KinectRecorder(KinectRecordOptions.Color, recordStream);
            recorder = new KinectRecorder(KinectRecordOptions.Color | KinectRecordOptions.Skeletons, recordStream);
            //recorder = new KinectRecorder(KinectRecordOptions.Skeletons, recordStream);
            Thread newWindowThread = new Thread(new ThreadStart(DisplayRecordTime));
            newWindowThread.SetApartmentState(ApartmentState.STA);
            newWindowThread.IsBackground = true;
            newWindowThread.Start();

        }
        private void DisplayRecordTime()
        {
            time.AutoReset = true;
            time.Enabled = true;
            time.Elapsed += new ElapsedEventHandler(time_Elapsed);
        }
        int i = 0;
        private void time_Elapsed(object source, ElapsedEventArgs e)
        {
            RecordBtn.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
        (Action)delegate() { RecordBtn.Content = "STOP ( " + i + "S )"; });
            i++;
        }

        private void ReplayBtn_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog replayFileDialog = new OpenFileDialog { Title = "Select filename", Filter = "Replay files|*.replay" };

            if (replayFileDialog.ShowDialog() == true)
            {
                if (replay != null)
                {
                    replay.SkeletonFrameReady -= replay_SkeletonFrameReady;
                    replay.ColorImageFrameReady -= replay_ColorImageFrameReady;
                    replay.Stop();
                }
                Stream recordStream = File.OpenRead(replayFileDialog.FileName);

                replay = new KinectReplay(recordStream);

                replay.SkeletonFrameReady += replay_SkeletonFrameReady;
                replay.ColorImageFrameReady += replay_ColorImageFrameReady;
                ReplayColorImageFrame frame = new ReplayColorImageFrame();

                replay.Start();


            }
        }

        private void replay_SkeletonFrameReady(object sender, ReplaySkeletonFrameReadyEventArgs e)
        {

            ProcessFrame(e.SkeletonFrame);
        }
        private void replay_ColorImageFrameReady(object sender, ReplayColorImageFrameReadyEventArgs e)
        {

            colorManager.Update(e.ColorImageFrame);
            //long timeSpan = e.ColorImageFrame.TimeStamp;

            Thread newWindowThread = new Thread(new ParameterizedThreadStart(TimeSpanDisplay));
            newWindowThread.SetApartmentState(ApartmentState.STA);
            newWindowThread.IsBackground = true;
            newWindowThread.Start(e.ColorImageFrame);

        }

        private void TimeSpanDisplay(object timeSpan)
        {
            ReplayColorImageFrame f = (ReplayColorImageFrame)timeSpan;

            TimeSpanLabel.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
        (Action)delegate() { TimeSpanLabel.Content = f.TimeStamp; });
        }

        private void EditBtn_Click(object sender, RoutedEventArgs e)
        {
            EditWindow w = new EditWindow();
            this.IsEnabled = false;
            w.Show();
            
        }


    }
}
